package service

import (
	"errors"

	"GinAdmin/core/database"
	"GinAdmin/model"

	"gorm.io/gorm"
)

// MenuService 菜单服务
type MenuService struct {
	db *gorm.DB
}

// NewMenuService 创建菜单服务
func NewMenuService() *MenuService {
	return &MenuService{
		db: database.DB,
	}
}

// GetMenuByID 根据ID获取菜单
func (s *MenuService) GetMenuByID(id uint) (*model.Menu, error) {
	var menu model.Menu
	if err := s.db.First(&menu, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("菜单不存在")
		}
		return nil, err
	}
	return &menu, nil
}

// GetMenuList 获取菜单列表
func (s *MenuService) GetMenuList(params *model.MenuSearchParams) ([]model.Menu, error) {
	var menus []model.Menu
	query := s.db.Model(&model.Menu{})

	if params.Title != "" {
		query = query.Where("title LIKE ?", "%"+params.Title+"%")
	}

	if params.Path != "" {
		query = query.Where("path LIKE ?", "%"+params.Path+"%")
	}

	if params.Status != 0 {
		query = query.Where("status = ?", params.Status)
	}

	if params.Type != 0 {
		query = query.Where("type = ?", params.Type)
	}

	if err := query.Order("sort ASC").Find(&menus).Error; err != nil {
		return nil, err
	}

	return menus, nil
}

// BuildTreeMenu 构建树形菜单
func (s *MenuService) BuildTreeMenu(menus []model.Menu, parentID uint) []map[string]interface{} {
	tree := make([]map[string]interface{}, 0)
	for _, menu := range menus {
		if menu.ParentID == parentID {
			node := make(map[string]interface{})
			node["id"] = menu.ID
			node["title"] = menu.Title
			node["name"] = menu.Name
			node["path"] = menu.Path
			node["component"] = menu.Component
			node["icon"] = menu.Icon
			node["sort"] = menu.Sort
			node["hidden"] = menu.Hidden
			node["status"] = menu.Status
			node["type"] = menu.Type
			node["permission"] = menu.Permission
			node["parent_id"] = menu.ParentID
			node["created_at"] = menu.CreatedAt
			node["updated_at"] = menu.UpdatedAt

			children := s.BuildTreeMenu(menus, menu.ID)
			if len(children) > 0 {
				node["children"] = children
			}
			tree = append(tree, node)
		}
	}
	return tree
}

// CreateMenu 创建菜单
func (s *MenuService) CreateMenu(req *model.CreateMenuRequest) (*model.Menu, error) {
	menu := model.Menu{
		ParentID:   req.ParentID,
		Path:       req.Path,
		Name:       req.Name,
		Component:  req.Component,
		Redirect:   req.Redirect,
		Title:      req.Title,
		Icon:       req.Icon,
		Sort:       req.Sort,
		Hidden:     req.Hidden,
		Type:       req.Type,
		Cache:      req.Cache,
		Status:     req.Status,
		Permission: req.Permission,
		ActiveMenu: req.ActiveMenu,
		Breadcrumb: req.Breadcrumb,
	}

	if err := s.db.Create(&menu).Error; err != nil {
		return nil, err
	}

	return &menu, nil
}

// UpdateMenu 更新菜单
func (s *MenuService) UpdateMenu(id uint, req *model.UpdateMenuRequest) (*model.Menu, error) {
	var menu model.Menu
	if err := s.db.First(&menu, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("菜单不存在")
		}
		return nil, err
	}

	// 构造更新数据
	updates := make(map[string]interface{})
	if req.ParentID != 0 {
		updates["parent_id"] = req.ParentID
	}
	if req.Path != "" {
		updates["path"] = req.Path
	}
	if req.Name != "" {
		updates["name"] = req.Name
	}
	if req.Component != "" {
		updates["component"] = req.Component
	}
	if req.Redirect != "" {
		updates["redirect"] = req.Redirect
	}
	if req.Title != "" {
		updates["title"] = req.Title
	}
	if req.Icon != "" {
		updates["icon"] = req.Icon
	}
	updates["sort"] = req.Sort
	if req.Hidden != nil {
		updates["hidden"] = *req.Hidden
	}
	if req.Type != 0 {
		updates["type"] = req.Type
	}
	if req.Cache != nil {
		updates["cache"] = *req.Cache
	}
	if req.Status != 0 {
		updates["status"] = req.Status
	}
	if req.Permission != "" {
		updates["permission"] = req.Permission
	}
	if req.ActiveMenu != "" {
		updates["active_menu"] = req.ActiveMenu
	}
	if req.Breadcrumb != nil {
		updates["breadcrumb"] = *req.Breadcrumb
	}

	if err := s.db.Model(&menu).Updates(updates).Error; err != nil {
		return nil, err
	}

	// 重新加载菜单信息
	if err := s.db.First(&menu, id).Error; err != nil {
		return nil, err
	}

	return &menu, nil
}

// DeleteMenu 删除菜单
func (s *MenuService) DeleteMenu(id uint) error {
	// 检查是否有子菜单
	var count int64
	if err := s.db.Model(&model.Menu{}).Where("parent_id = ?", id).Count(&count).Error; err != nil {
		return err
	}
	if count > 0 {
		return errors.New("存在子菜单，无法删除")
	}

	// 检查是否有角色关联
	if err := s.db.Table("go_role_menu").Where("menu_id = ?", id).Count(&count).Error; err != nil {
		return err
	}
	if count > 0 {
		return errors.New("该菜单已关联角色，无法删除")
	}

	var menu model.Menu
	if err := s.db.First(&menu, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("菜单不存在")
		}
		return err
	}

	return s.db.Delete(&menu).Error
}

// GetMenuTree 获取菜单树
func (s *MenuService) GetMenuTree() ([]map[string]interface{}, error) {
	var menus []model.Menu
	if err := s.db.Order("sort ASC").Find(&menus).Error; err != nil {
		return nil, err
	}

	return s.BuildTreeMenu(menus, 0), nil
}

// GetMenusByRoleID 获取角色菜单
func (s *MenuService) GetMenusByRoleID(roleID uint) ([]model.Menu, error) {
	var role model.Role
	if err := s.db.Preload("Menus").First(&role, roleID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("角色不存在")
		}
		return nil, err
	}

	return role.Menus, nil
}

// GetUserMenuTree 获取用户菜单树
func (s *MenuService) GetUserMenuTree(userID uint) ([]map[string]interface{}, error) {
	// 获取用户角色
	var user model.User
	if err := s.db.Preload("Roles").First(&user, userID).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("用户不存在")
		}
		return nil, err
	}

	if len(user.Roles) == 0 {
		return []map[string]interface{}{}, nil
	}

	// 获取角色菜单 (去重)
	var roleIDs []uint
	for _, role := range user.Roles {
		roleIDs = append(roleIDs, role.ID)
	}

	var menus []model.Menu
	if err := s.db.Distinct().
		Joins("JOIN go_role_menu ON go_role_menu.menu_id = go_menu.id").
		Where("go_role_menu.role_id IN ? AND go_menu.status = 1", roleIDs).
		Order("go_menu.sort ASC").
		Find(&menus).Error; err != nil {
		return nil, err
	}

	return s.BuildTreeMenu(menus, 0), nil
}
